package com.explorati.design_pattern.creational.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 懒汉单例模式的实现
 * 
 * @author explorati
 *
 */
public class LazySingleton {

	private static LazySingleton lazySingleton = null;
	// private static boolean flag = true;

	// 防止外部new
	private LazySingleton() {

		if (lazySingleton != null) {
			throw new IllegalArgumentException("单例模式禁止反射调用");
		}

		// 这种方法防止了先调用反射带来的错误(可创建两个不同的对象),但是反射的威力不止这么点，还是可以破坏的
		// if (flag) {
		// flag = false;
		// } else {
		// throw new IllegalArgumentException("单例构造器禁止反射调用");
		// }

		// 此种方法只是用于类加载时就创建对象的情况，在懒汉中若如此使用
		// 则会根据反射调用顺序来决定，如果反射调用在前面，则创建会两个不同对象
		// if (lazySingleton != null) {
		// throw new IllegalArgumentException("单例模式禁止反射调用");
		// }
	}

	/**
	 * 在静态方法上加上synchronized关键字，锁住的这个类的class文件 如果不是静态方法，锁的是堆内存中生成的对象
	 * 
	 * @return
	 */
	// 同步锁消耗资源，加锁解锁开销较大，而且synchronized修饰static方法的时候锁的是这个类，范围大，性能不好
	public synchronized static LazySingleton getInstance() {
		// 和在静态方法上加关键字作用一样
		// synchronized (LazySingleton.class) {
		// if (lazySingleton == null) {
		// lazySingleton = new LazySingleton();
		// }
		// return lazySingleton;
		// }

		if (lazySingleton == null) {
			lazySingleton = new LazySingleton();
		}
		return lazySingleton;
	}

	// 测试单例的解决方法(添加属性判断)
	// public static void main(String[] args) throws NoSuchMethodException,
	// SecurityException, InstantiationException,
	// IllegalAccessException, IllegalArgumentException,
	// InvocationTargetException, NoSuchFieldException {
	// Class objectClass = LazySingleton.class;
	// Constructor constructor = objectClass.getDeclaredConstructor();
	// constructor.setAccessible(true);
	//
	// LazySingleton o1 = LazySingleton.getInstance();
	//
	// // 通过此种方法改变flag破坏单例，所以说不管构造器里面加多复杂的逻辑，都是没有用的
	// Field flag = o1.getClass().getDeclaredField("flag");
	// flag.setAccessible(true);
	// flag.set(o1, true);
	// LazySingleton o2 = (LazySingleton) constructor.newInstance();
	//
	// System.out.println(o1);
	// System.out.println(o2);
	// System.out.println(o1 == o2);
	//
	// }
}
